/*
    SDL - Simple DirectMedia Layer
    Copyright (C) 1997-2009 Sam Lantinga

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

    Sam Lantinga
    slouken@libsdl.org
*/

#include <cell/mstream.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h.>

static int32_t			MP3Streams[4] = {-1, -1, -1. -1};

struct					_MP3Data
{
	uint8_t*			Data;
	uint32_t			Location;
	uint32_t			Size;

	uint32_t			StreamDead;
	uint8_t*			Buffers[2];
}	MP3Data[4];

static void				MP3StreamCallback		(int streamNumber, void * userData, int cType, void * pWriteBuffer, int nBufferSize)
{
	struct _MP3Data* myData = (struct _MP3Data*)userData;

	if((cType == CELL_MS_CALLBACK_MOREDATA))
	{
		/* TODO: This won't work for very small files ... */
		if((myData->Size - myData->Location) >= nBufferSize)
		{
			memcpy(pWriteBuffer, &myData->Data[myData->Location], nBufferSize);
			myData->Location += nBufferSize;
		}
		else
		{
			int left = myData->Size - myData->Location;
			memcpy(pWriteBuffer, &myData->Data[myData->Location], left);
			memcpy(pWriteBuffer, &myData->Data[0], nBufferSize - left);
			myData->Location = left;
		}
	}
	else if(cType == CELL_MS_CALLBACK_FINISHSTREAM)
	{
		myData->StreamDead = 1;
	}
}

int32_t					CELL_PlayMP3			(const char* aFileName, int32_t aLoop)
{
	/* Find a free stream */
	int32_t index = -1;
	for(int i = 0; i != 4; i ++)
	{
		if(MP3Streams[i] == -1)
		{
			index = i;
			break;
		}
	}

	if(index == -1)
	{
		return -1;
	}

	/* Check the file */
	struct stat statbuf;
	if(stat(aFileName, &statbuf))
	{
		return -1;
	}

	MP3Data[index].Data = memalign(128, statbuf.st_size);
	MP3Data[index].Location = 0;
	MP3Data[index].Size = statbuf.st_size;
	MP3Data[index].StreamDead = 0;
	MP3Data[index].Buffers[0] = memalign(128, 4096);
	MP3Data[index].Buffers[1] = memalign(128, 4096);

	/* Load the file */
	FILE* mp3 = fopen(aFileName, "r");
	fread(MP3Data[index].Data, 1, statbuf.st_size, mp3);
	fclose(mp3);

	/* Init the buffers */
	memcpy(MP3Data[index].Buffers[0], MP3Data[index].Data, 4096);
	memcpy(MP3Data[index].Buffers[1], &MP3Data[index].Data[4096], 4096);
	MP3Data[index].Location = 8192;

	/* TODO: Detect freq and channels */
	CellMSInfo StreamInfo = {CELL_MS_MASTER_BUS, MP3Data[index].Buffers[0], 4096, MP3Data[index].Buffers[1], 4096, 44100, 2, 0, CELL_MS_MP3, CELL_MS_STREAM_NOFLAGS};

    MP3Streams[index] = cellMSStreamOpen();

    cellMSStreamSetInfo(MP3Streams[index], &StreamInfo);
	cellMSCoreSetVolume1(MP3Streams[index], CELL_MS_DRY, CELL_MS_SPEAKER_FL, CELL_MS_CHANNEL_0, 1.0f);
	cellMSCoreSetVolume1(MP3Streams[index], CELL_MS_DRY, CELL_MS_SPEAKER_FR, CELL_MS_CHANNEL_1, 1.0f);
    cellMSStreamSetCallbackFunc(MP3Streams[index], MP3StreamCallback);
	cellMSStreamSetCallbackData(MP3Streams[index], &MP3Data[index]);
	cellMSStreamPlay(MP3Streams[index]);

	return index;
}

void					CELL_CloseMP3			(int32_t aStream)
{
	if(aStream >= 0 && aStream < 4 && MP3Streams[aStream] >= 0)
	{
		cellMSStreamSetSecondRead(MP3Streams[aStream], 0, 0);
		while(!MP3Data[aStream].StreamDead); //?
		cellMSStreamClose(MP3Streams[aStream]);
		while(!(cellMSStreamGetStatus(MP3Streams[aStream]) & CELL_MS_STREAM_CLOSED));

		free(MP3Data[aStream].Data);
		free(MP3Data[aStream].Buffers[0]);
		free(MP3Data[aStream].Buffers[1]);
		memset(&MP3Data[aStream], 0, sizeof(MP3Data[0]));

		MP3Streams[aStream] = -1;
	}
}

